package org.web.base.helper.sensitive;

import org.web.base.domain.ResultDO;

import java.lang.reflect.Field;
import java.util.*;

public class SensitiveDataHelper {

    private static final String TELEPHONE_FORMAT = "(\\d{3})\\d{4}(\\d{4})";

    private static final Map<String, List<Field>> CACHE_MAP = new HashMap<>();


    public static void desensitize(Object obj) {
        if (obj == null) {
            throw new IllegalArgumentException("Object cannot be null");
        }

        List<Field> listInCache = CACHE_MAP.get(obj.getClass().getName());
        if (listInCache == null) {
            listInCache = getFieldsToProcess(obj);
        }

        for (Field field : listInCache) {
            try {
                Object value = field.get(obj);
                if (value != null) {
                    SensitiveType type = field.getAnnotation(SensitiveData.class).value();
                    String desensitizedValue = desensitizeValue(value.toString(), type);
                    field.set(obj, desensitizedValue);
                }
            } catch (IllegalAccessException e) {
                throw new IllegalArgumentException("Unable to access field: " + field.getName(), e);
            }
        }
    }

    private static List<Field> getFieldsToProcess(Object obj) {
        List<Field> listInCache = new ArrayList<>();
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(SensitiveData.class)) {
                field.setAccessible(true);
                listInCache.add(field);
            }
        }
        CACHE_MAP.put(obj.getClass().getName(), listInCache);
        return listInCache;
    }

    private static String desensitizeValue(String value, SensitiveType type) {
        switch (type) {
            case PHONE_NUMBER:
                return value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
            case EMAIL:
                int atIndex = value.indexOf("@");
                if (atIndex > 0) {
                    String prefix = value.substring(0, atIndex);
                    return prefix.replaceAll("(\\w)\\w+", "$1****") + value.substring(atIndex);
                } else {
                    return value;
                }
            case PASSWORD:
                return "******";
            case ID_CARD:
                return value.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2");
            case TELEPHONE:
                return value.replaceAll(TELEPHONE_FORMAT, "$1****$2");
            default:
                return value;
        }
    }

    public static <T> void desensitize(ResultDO<T> resultDO) {
        if (resultDO.isSuccess()) {
            T t = resultDO.getDomain();
            if (t instanceof Collection) {
                Collection<?> collection = (Collection<?>) t;
                for (Object item : collection) {
                    desensitize(item);
                }
            } else if (t instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) t;
                for (Object value : map.values()) {
                    desensitize(value);
                }
            } else {
                desensitize(t);
            }
        }
    }

}
